/*
 * Copyright (C) 2014 Miquel Sas
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package traderlib.core.data.db;

import java.util.ArrayList;
import java.util.Objects;

/**
 * A table foreign key.
 *
 * @author Miquel Sas
 */
public class ForeignKey extends ArrayList<ForeignKey.Segment> {

	/**
	 * Enumerate the ON DELETE actions
	 */
	public enum OnDelete {

		/**
		 * Constant for ON DELETE [NO ACTION|RESTRICT]
		 */
		RESTRICT,
		/**
		 * Constant for ON DELETE [CASCADE]
		 */
		CASCADE,
		/**
		 * Constant for ON DELETE [SET NULL]
		 */
		SET_NULL;
	}

	/**
	 * A segment packs the local and foreign columns.
	 */
	public static class Segment {

		/**
		 * The local column.
		 */
		private Column localColumn = null;

		/**
		 * The foreign column.
		 */
		private Column foreignColumn = null;

		/**
		 * Default constructor.
		 */
		public Segment() {
			super();
		}

		/**
		 * Constructor assigning the columns.
		 *
		 * @param localColumn The local column.
		 * @param foreignColumn The foreign column.
		 */
		public Segment(Column localColumn, Column foreignColumn) {
			super();
			this.localColumn = localColumn;
			this.foreignColumn = foreignColumn;
		}

		/**
		 * Get the local column.
		 *
		 * @return The local column.
		 */
		public Column getLocalColumn() {
			return localColumn;
		}

		/**
		 * Get the foreign column.
		 *
		 * @return The foreign column.
		 */
		public Column getForeignColumn() {
			return foreignColumn;
		}

		/**
		 * Set the local column.
		 *
		 * @param localColumn The local column.
		 */
		public void setLocalColumn(Column localColumn) {
			this.localColumn = localColumn;
		}

		/**
		 * Set the foreign column.
		 *
		 * @param foreignColumn The foreign column.
		 */
		public void setForeignColumn(Column foreignColumn) {
			this.foreignColumn = foreignColumn;
		}

		/**
		 * Appends this segment to an SQL select construction.
		 *
		 * @param b The string builder where the SQL query is being appended.
		 */
		public void appendToSQL(StringBuilder b) {
			b.append(localColumn.getNameRelate());
			b.append(" = ");
			b.append(foreignColumn.getNameRelate());
		}

		/**
		 * Returns the hash code for this order key.
		 *
		 * @return The hash code
		 */
		@Override
		public int hashCode() {
			int hash = 0;
			hash ^= localColumn.hashCode();
			hash ^= foreignColumn.hashCode();
			return hash;
		}

		/**
		 * Check wheter the argument object is equal to this order segment.
		 *
		 * @param obj The object to compare
		 * @return A boolean.
		 */
		@Override
		public boolean equals(Object obj) {
			if (obj == null) {
				return false;
			}
			if (getClass() != obj.getClass()) {
				return false;
			}
			final Segment other = (Segment) obj;
			if (!Objects.equals(this.localColumn, other.localColumn)) {
				return false;
			}
			return Objects.equals(this.foreignColumn, other.foreignColumn);
		}

		/**
		 * Returns a string representation of this segment.
		 *
		 * @return A string
		 */
		@Override
		public String toString() {
			StringBuilder b = new StringBuilder(64);
			b.append(getLocalColumn().getName());
			b.append(" -> ");
			b.append(getForeignColumn().getName());
			return b.toString();
		}
	}
	/**
	 * The name of this constraint.
	 */
	private String name = null;

	/**
	 * The local table.
	 */
	private Table localTable = null;

	/**
	 * The foreign table.
	 */
	private Table foreignTable = null;

	/**
	 * The type of deletion restriction: default RESTRICT.
	 */
	private OnDelete deleteRestriction = OnDelete.RESTRICT;

	/**
	 * Default constructor.
	 */
	public ForeignKey() {
		super();
	}

	/**
	 * Add a segment to this foreign key.
	 *
	 * @param localColumn The local column.
	 * @param foreignColumn The foreign column.
	 */
	public void add(Column localColumn, Column foreignColumn) {
		add(new ForeignKey.Segment(localColumn, foreignColumn));
	}

	/**
	 * Get the name of this foreign key.
	 *
	 * @return The foreign key name
	 */
	public String getName() {
		return name;
	}

	/**
	 * Set the name of this foreign key.
	 *
	 * @param name The name
	 */
	public void setName(String name) {
		this.name = name;
	}

	/**
	 * Get the local table.
	 *
	 * @return The local table
	 */
	public Table getLocalTable() {
		return localTable;
	}

	/**
	 * Set the local table.
	 *
	 * @param localTable The local table
	 */
	public void setLocalTable(Table localTable) {
		this.localTable = localTable;
	}

	/**
	 * Getthe foreign table.
	 *
	 * @return The foreign table.
	 */
	public Table getForeignTable() {
		return foreignTable;
	}

	/**
	 * Set the foreign table.
	 *
	 * @param foreignTable The foreign table
	 */
	public void setForeignTable(Table foreignTable) {
		this.foreignTable = foreignTable;
	}

	/**
	 * Get the delete restriction.
	 *
	 * @return The delete restriction.
	 */
	public OnDelete getDeleteRestriction() {
		return deleteRestriction;
	}

	/**
	 * Set the delete restriction.
	 *
	 * @param deleteRestriction The delete restriction.
	 */
	public void setDeleteRestriction(OnDelete deleteRestriction) {
		this.deleteRestriction = deleteRestriction;
	}

	/**
	 * Return a string representation of this foreign key.
	 *
	 * @return The string representation.
	 */
	@Override
	public String toString() {
		StringBuilder b = new StringBuilder(64);
		b.append(getLocalTable().getName());
		b.append(" -> ");
		b.append(getForeignTable().getName());
		return b.toString();
	}

	/**
	 * Returns the hashcode for this object.
	 *
	 * @return The hascode.
	 */
	@Override
	public int hashCode() {
		int hash = 0;
		hash ^= Objects.hashCode(this.name);
		hash ^= Objects.hashCode(this.localTable);
		hash ^= Objects.hashCode(this.foreignTable);
		hash ^= Objects.hashCode(this.deleteRestriction);
		return hash;
	}

	/**
	 * Check if the argument object is equal to this foreign key.
	 *
	 * @param obj The object to compare for equality.
	 * @return A boolean
	 */
	@Override
	public boolean equals(Object obj) {
		if (obj == null) {
			return false;
		}
		if (getClass() != obj.getClass()) {
			return false;
		}
		final ForeignKey other = (ForeignKey) obj;
		if (!Objects.equals(this.name, other.name)) {
			return false;
		}
		if (!Objects.equals(this.localTable, other.localTable)) {
			return false;
		}
		if (!Objects.equals(this.foreignTable, other.foreignTable)) {
			return false;
		}
		if (this.deleteRestriction != other.deleteRestriction) {
			return false;
		}
		for (int i = 0; i < size(); i++) {
			if (!get(i).equals(other.get(i))) {
				return false;
			}
		}
		return true;
	}
}
